//
// Created by Abstergo on 2024/6/18.
//

#ifndef TBS_CPP_LINKLIST_HPP
#define TBS_CPP_LINKLIST_HPP

#include <base/base.hpp>
#include <structs/Iterable.h>

namespace tbs::structs::link_list {
template<typename V> class LinkNode {
private:
  using self = LinkNode<V>;
  V _data;
  self *_pre = nullptr;
  self *_after = nullptr;

public:
  CONST V &value() CONST;

  V &value();

  bool has_pre() CONST;

  bool has_after() CONST;

  self *&pre();

  self *&after();

  CONST self *after() CONST;

  CONST self *pre() CONST;

  operator V &();

  operator V() CONST;
};

#include "inls/structs/LinkNodeInl.cuh"
template<typename T> static inline void connectAfter(LinkNode<T> &target, LinkNode<T> &other);
template<typename T> static inline void disconnect(LinkNode<T> &target, LinkNode<T> *&pre, LinkNode<T> *&after);
template<typename V> void connectAfter(LinkNode<V> &target, LinkNode<V> &other) {
  if (other.has_pre()) {
	throw tbs::base_error("the node had pre node.can not connect to target");
  }
  if (!target.has_after()) {
	target.after() = &other;
	other.pre() = &target;
	return;
  }
  if (other.has_after()) {
	throw tbs::base_error("the node and target all had after node ,can not connect");
  }
  target.after()->pre() = &other;
  other.after() = target.after();
  target.after() = &other;
  other.pre() = &target;
}
template<typename V> void disconnect(LinkNode<V> &target, LinkNode<V> *&pre, LinkNode<V> *&after) {
  pre = target.pre();
  if (pre != nullptr) {
	pre->after() = nullptr;
  }
  after = target.after();
  if (after != nullptr) {
	after->pre() = nullptr;
  }
  target.pre() = nullptr;
  target.after() = nullptr;
}

template<typename T> class NodeIterator : public tbs::structs::Iterator<LinkNode<T> > {
private:
  using node = LinkNode<T>;
  node *_b = nullptr, *_i = nullptr;
  size_t _index = 0;

public:
  explicit NodeIterator(node *b);

  virtual tbs::structs::Iterator<LinkNode<T> > &next() override;

  virtual bool has_next() CONST override;

  virtual LinkNode<T> &value() override;

  CONST LinkNode<T> &value() CONST;

  virtual const void *source() CONST override;

  virtual const size_t index() CONST override;

  virtual bool equals(const tbs::structs::Iterator<LinkNode<T> > &other) CONST override;
};

#include "inls/structs/NodeIteratorInl.cuh"

template<typename T> class LinkList : public tbs::structs::Iterable<NodeIterator<T> > {
private:
  using node = LinkNode<T>;
  node _head;
  node *_tail = &_head;

public:
  /**
  * @brief void(node& now, node& tail, node& head, const size_t& index,
	  bool& stop)
   */
  using node_operate_function = std::function<void(node &now, node &tail, node &head, const size_t &index,
												   bool &stop)>;
  virtual ~LinkList();

  LinkList();

  LinkList(CONST LinkList &other);

  LinkList(LinkList &&other) NO_EXCEPT;

  LinkList &operator=(CONST LinkList &other);

  LinkList &operator=(LinkList &&other) NO_EXCEPT;

  void insert(CONST size_t &index, T &&val);

  void insert(CONST size_t &index, CONST T &val);

  void merge(LinkList &&other);

  void append(T &&value);

  void append_with_copy(CONST T &value);

  void clear();

  void operateNode(node_operate_function _f, bool is_reverse = false);

  virtual NodeIterator<T> begin() NO_EXCEPT override;

  virtual NodeIterator<T> end() NO_EXCEPT override;

  NodeIterator<T> begin() CONST NO_EXCEPT;

  NodeIterator<T> end() CONST NO_EXCEPT;
};

#include "inls/structs/LinkListInl.cuh"
}

#endif //TBS_CPP_LINKLIST_HPP
